//1、 模式是Rust中特殊的语法, 模式用来匹配值的结构
//
//2、 模式由如下内容组成:
//(1) 字面值
//(2) 解构的数组、枚举、结构体或则元组
//(3) 变量
//(4) 通配符
//(5) 占位符

use std::option::Option::Some;

fn main() {
  println!("Hello, patterns-and-matching!");

  /** 1. match*/
  /*
    match VALUE {
      PATTERN => EXPRESSION,
      PATTERN => EXPRESSION,
      PATTERN => EXPRESSION,
      _ => default to do  //必须是穷尽的
    }
  */
  let a = 1;
  match a {
    0 => println!("Zero"),
    1 => println!("One"),
    //match 必须比配所有情况, 这里的 _ 就相当于默认匹配
    _ => println!("default")
  }

  /** 2. if let*/
  let color: Option<&str> = None;
  let is_ok = true;
  let age: Result<u8, _/*todo 忽略错误, 什么情况可以忽略？*/> = "33".parse();

  if let Some(c) = color { //如果有值就走这
    println!("{}", c);

    //if let 可以 和普通的if组合起来使用
  } else if is_ok {
    println!("is ok");
  } else if let Ok(a) = age {
    if a > 30 {
      println!("oh, mature man");
    } else {
      println!("oh, young man");
    }
  } else {
    println!("in else");
  }


  /** 3: while let*/
  let mut stack = Vec::new();
  stack.push(1);
  stack.push(2);
  stack.push(3);

  //pop: Removes the last element from a vector and returns it, or None if it is empty.
  //pub fn pop(&mut self) -> Option<T>
  while let Some(top) = stack.pop() {
    println!("top = {}", top);
  } // 只要匹配 Some(value), 就会一直循环


  /** 4: 在for循环中, 模式是直接跟随for关键字的值, 例如 for x in y, x 是对应的模式
           下面的例子中 模式就是 ---> (index, value) , 一个元组*/
  let v = vec!['a', 'b', 'c'];

  // todo v.iter() ---> v是slice? .iter 说的是要用在slice上
  // slice 是除了&引用外, 能够不夺取原变量所有权并且还能使用其数据的数据结构。
  // slice 允许你引用集合中一段连续的元素序列，而不用引用整个集合。
  // slice 是 String 中一部分值的引用

  //此时的模式是 (index, value)
  for (index, value) in v.iter().enumerate() { // iter 方法返回集合中的每一个元素，而 enumerate 包装了 iter 的结果，将这些元素作为元组的一部分来返回。enumerate 返回的元组中，第一个元素是索引，第二个元素是集合中元素的引用。这比我们自己计算索引要方便一些。
    println!("index: {}, value: {}", index, value);
    //index: 0, value: a
    // index: 1, value: b
    // index: 2, value: c
  }
  println!("{:?}", v); //['a', 'b', 'c']


  /** 5: let语句*/
  //let PATTERN = EXPRESSION
  // 下面的例子 (1,2,3) 会匹配 (x,y,z) 将1绑定到x, 2绑定到y, 3绑定到z
  let (x, y, z) = (1, 2, 3);
  println!("x:{}", x); //x:1
  println!("y:{}", y); //y:2
  println!("z:{}", z); //z:3

  let (x, .. /*貌似也可以用 _ */, z) = (1, 2, 3);
  // 这里 ..  表示忽略
  println!("{},{}", x, z);

  /**6. 函数的参数也是模式*/
  fn print_point(&(x, y): &(i32, i32)) {
    println!("x:{},y:{}", x, y);
  }
  print_point(&(1, 2)); //x:1,y:2
  let x = (12, 23);
  print_point(&x); //x:12,y:23
  println!("x.1 = {}", x.1); //x.1 = 23
  // print_point((1, 2)); //expected `&(i32, i32)`, found `(i32, i32)`


  fn print_point2((x, y): (i32, i32)) {
    println!("x:{},y:{}", x, y);
  }
  print_point2(x); //x:12,y:23 //todo ↓ 并不会失去所有权 emmm  为嘛加&?
  println!("x.1 = {}", x.1); //x.1 = 23



  //todo 模式在使用它的地方 并不都是相同的 ---> 模式存在不可反驳 和 可反驳的

}


